#ifndef ALFS_POINTERS_REF_COUNTED_DELETER_HPP
#define ALFS_POINTERS_REF_COUNTED_DELETER_HPP
#include    <alfs/config.hpp>

// File [alfs/pointers/RefCountedDeleter.hpp].
//
// alfs::AbstractRefCountedDeleter.
// alfs::RefCountedDeleter<>.
// Reference counting support for smart pointers.  In a smart pointer class
// one may use boost::intrusive_ptr to manage a shared RefCountedDeleter.
// For example usage see <alfs/pointers/IntrusivePtr.hpp>.
//
// (c) copyright Alf P. Steinbach 2008.
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php>.

#include    <boost/intrusive_ptr.hpp>                       // boost::intrusive_ptr<>
#include    <alfs/stdx/memory.hpp>                          // alfs::destroyPointee
#include    <alfs/stdx/static_assert.hpp>                   // static_assert
#include    <cassert>                                       // assert
#include    <cstddef>                                       // std::size_t

namespace alfs {

#   define   ThisClass  AbstractRefCountedDeleter
    class ThisClass
    {
    private:

        std::size_t  myRefCount;

        ThisClass( ThisClass const& );              // No such.
        ThisClass& operator=( ThisClass const& );   // No such.

    protected:
        ThisClass() throw(): myRefCount( 1 ) {}
        virtual ~ThisClass() throw() {}

    public:
        virtual void* clear() throw() = 0;
        virtual bool isVoid() const throw() = 0;

        void addRef() throw() { ++myRefCount; }

        void release() throw()
        {
            --myRefCount;
            if( myRefCount == 0 ) { delete this; }
        }
    };
#   undef   ThisClass

    inline void intrusive_ptr_add_ref( AbstractRefCountedDeleter* p )
    {
        p->addRef();
    }

    inline void intrusive_ptr_release( AbstractRefCountedDeleter* p )
    {
        p->release();
    }


#   define  ThisClass   RefCountedDeleter

    template< typename T >
    class ThisClass
        : public AbstractRefCountedDeleter
    {
    private:

        T*      myReferent;

        ThisClass( ThisClass const& );              // No such.
        ThisClass& operator=( ThisClass const& );   // No such.

        virtual void onCleared() throw() {}

    protected:
        virtual ~ThisClass() throw()
        {
            ::alfs::destroyPointee( myReferent );
        }

        ThisClass( T* p ) throw()
            : myReferent( p )
        {
            assert( myReferent != 0 );
        }

    public:
        static ThisClass* createWith( T* p )
        {
            // TODO: Replace this with ownership-transfer smart pointer using alfs::destroyPointee.
            try
            {
                return new ThisClass( p );
            }
            catch( ... )
            {
                alfs::destroyPointee( p );
                throw;
            }
        }
 
        T* referent() const throw() { return myReferent; }

        virtual void* clear() throw()
        {
            void* const result = myReferent;

            myReferent = 0;  onCleared();
            return result;
        }

        virtual bool isVoid() const throw()
        {
            return myReferent == 0;
        }
    };
#   undef   ThisClass

}  // alfs

#endif
